/*
 * ComponentDelegate.cpp  0.4.0 / Nov 17, 2010
 *
 * Copyright (c) 2010 - 2011, cute4j.com and contributors.
 *
 * This software is licensed under the LGPL version 2.1 license.
 * A copy of this license is included in the file LICENSE-LGPL.txt.
 */
#include "ComponentDelegate.h"

#include "QCursorAdapter.h"
#include "SwingDelegate.h"
#include "SwingGraphics.h"
#include "QWidgetActionAdapter.h"
#include "ContainerDelegate.h"
#include "ToolTipDelegate.h"
#include "WhatsThisManagerDelegate.h"

// ComponentDelegate :: Protected Constructors. --------------------------------

/*!
 * \brief Constructs new ComponentDelegate object.
 *
 * \param env the JNIEnv pointer
 * \param obj the Swing java object
 * \param widget the Qt widget
 */
ComponentDelegate::ComponentDelegate(JNIEnv *env, jobject obj, QWidget *widget)
  : QObjectDelegate(env, obj, widget), m_eventFilterEnabled(true),
    m_enabledEvents(0), m_currentEvent(0), m_paintEvent(0),
    m_previousEventType(0), m_previousKey(0),
    m_previousMouseButton(Qt::NoButton), m_previousMouseX(0),
    m_previousMouseY(0), m_parentDelegate(0), m_widget(widget), m_action(0)
{
  Q_ASSERT(JNISwingWrapper::isSwingThread(env));
  Q_ASSERT(m_widget);
}

/*!
 * \brief Constructs new ComponentDelegate object.
 *
 * \param env the JNIEnv pointer
 * \param obj the java object
 */
ComponentDelegate::ComponentDelegate(JNIEnv *env, jobject obj)
  : QObjectDelegate(env, obj, new QWidget()), m_eventFilterEnabled(true),
    m_enabledEvents(0), m_currentEvent(0), m_paintEvent(0),
    m_previousEventType(0), m_previousKey(0),
    m_previousMouseButton(Qt::NoButton), m_previousMouseX(0),
    m_previousMouseY(0), m_parentDelegate(0), m_action(0)
{
  Q_ASSERT(JNISwingWrapper::isSwingThread(env));
  m_widget = qobject_cast<QWidget *>(qObject());
  Q_ASSERT(m_widget);
}

// ComponentDelegate :: Private Constructor. -----------------------------------

ComponentDelegate::ComponentDelegate(JNIEnv *env, jobject obj, QAction *action)
  : QObjectDelegate(env, obj, action), m_enabledEvents(0),
    m_currentEvent(0), m_paintEvent(0), m_previousEventType(0),
    m_previousKey(0), m_previousMouseButton(Qt::NoButton), m_previousMouseX(0),
    m_previousMouseY(0), m_parentDelegate(0), m_widget(0), m_action(action)
{
  Q_ASSERT(JNISwingWrapper::isSwingThread(env));
}

// ComponentDelegate :: Protected Destructor. ----------------------------------

/*!
 * \brief Destroys the ComponentDelegate object.
 */
ComponentDelegate::~ComponentDelegate()
{
  if (notifyDelete()) {
    setDelegatePointer(0);
    jniObject()->callVoidMethod(disposeMID());
  }
  m_widget = 0;
  if (m_action) {
    delete m_action;
  }
}

// ComponentDelegate :: Native Calls. ------------------------------------------

/*!
 * \brief Shows/hides the Swing java object.
 *
 * \param env the JNIEnv pointer
 * \param visible if \c true the object will be shown
 */
void ComponentDelegate::setVisible(JNIEnv *env, jboolean visible)
{
  Q_ASSERT(env);
  SWING_REENTRANT(setVisible, SWING_ENV_ARG, JBOOLEAN_ARG(visible))
  m_widget->setVisible(visible);
}

/*!
 * \brief Shows Swing object for the first time.
 *
 * \param env the JNIEnv pointer
 */
void ComponentDelegate::showWindow(JNIEnv *env)
{
  Q_ASSERT(env);
  SWING_REENTRANT(showWindow, SWING_ENV_ARG)
  QString title = qObject()->objectName();
  if (title.isEmpty()) {
    m_widget->setWindowTitle(" ");  // avoids "javaw" title
  } else {
    m_widget->setWindowTitle(title);
  }
  if (!m_widget->testAttribute(Qt::WA_Resized)) {
    QSize preferred = getPreferredSize();
    if (preferred.isValid()) {
      m_widget->resize(preferred);
    } else {
      m_widget->adjustSize();
    }
  }
  m_widget->setVisible(true);
}

/*!
 * \brief Enables/disables the Swing object.
 *
 * \param env the JNIEnv pointer
 * \param enabled if \c true the object will be enabled
 */
void ComponentDelegate::setEnabled(JNIEnv *env, jboolean enabled)
{
  Q_ASSERT(env);
  SWING_REENTRANT(setEnabled, SWING_ENV_ARG, JBOOLEAN_ARG(enabled))
  m_widget->setEnabled(enabled);
}

/*!
 * \brief Sets focusable state of the component
 *
 * \param env the JNIEnv pointer 
 * \param focusable the focusable state
 */
void ComponentDelegate::setFocusable(JNIEnv *env, jboolean focusable)
{
  Q_ASSERT(env);
  SWING_REENTRANT(setFocusable, SWING_ENV_ARG, JBOOLEAN_ARG(focusable))
  if (focusable) {
    m_widget->setFocusPolicy(Qt::StrongFocus);
  } else {
    m_widget->setFocusPolicy(Qt::NoFocus);
  }
}

/*!
 * \brief Requests the focus.
 *
 * \param env the JNIEnv pointer 
 */
void ComponentDelegate::requestFocus(JNIEnv *env)
{
  Q_ASSERT(env);
  SWING_REENTRANT(requestFocus, SWING_ENV_ARG)
  m_widget->setFocus();
}

/*!
 * \brief Sets location of the component.
 *
 * \param env the JNIEnv pointer 
 * \param x the x coordinate of the location
 * \param y the y coordinate of the location
 */
void ComponentDelegate::setLocation(JNIEnv *env, jint x, jint y)
{
  Q_ASSERT(env);
  SWING_REENTRANT(setLocation, SWING_ENV_ARG, JINT_ARG(x), JINT_ARG(y))
  m_widget->move(x, y);
}

/*!
 * \brief Returns preferred size of the native widget.
 *
 * \param env the JNIEnv pointer 
 * 
 * \return preferred size of the native widget
 */
jobject ComponentDelegate::getPreferredSize(JNIEnv *env)
{
  Q_ASSERT(env);
  SWING_REENTRANT_RETURN(getPreferredSize, jobject, SWING_ENV_ARG)
  QSize sizeHint = m_widget->sizeHint();
  return DimensionObject::newObject(sizeHint.width(), sizeHint.height());
}

/*!
 * \brief Sets size of the component.
 *
 * \param env the JNIEnv pointer 
 * \param width the width of the component
 * \param height the height of the component
 */
void ComponentDelegate::setSize(JNIEnv *env, jint width, jint height)
{
  Q_ASSERT(env);
  SWING_REENTRANT(setSize, SWING_ENV_ARG, JINT_ARG(width), JINT_ARG(height))
  m_widget->resize(width, height);
}

/*!
 * \brief Sets component's maximum size.
 *
 * \param env the JNIEnv pointer 
 * \param width the maximum width
 * \param height the maximum height
 */
void ComponentDelegate::setMaximumSize(JNIEnv *env, jint width, jint height)
{
  Q_ASSERT(env);
  SWING_REENTRANT(setMaximumSize, SWING_ENV_ARG, JINT_ARG(width),
                  JINT_ARG(height))
  m_widget->setMaximumSize(width, height);
}

/*!
 * \brief Sets component's minimum size.
 *
 * \param env the JNIEnv pointer 
 * \param width the minimum width
 * \param height the minimum height
 */
void ComponentDelegate::setMinimumSize(JNIEnv *env, jint width, jint height)
{
  Q_ASSERT(env);
  SWING_REENTRANT(setMinimumSize, SWING_ENV_ARG, JINT_ARG(width),
                  JINT_ARG(height))
  m_widget->setMinimumSize(width, height);
}

/*!
 * \brief Sets componenet's fixed size.
 *
 * \param env the JNIEnv pointer 
 * \param width the fixed width
 * \param height the fixed height
 */
void ComponentDelegate::setFixedSize(JNIEnv *env, jint width, jint height)
{
  Q_ASSERT(env);
  SWING_REENTRANT(setFixedSize, SWING_ENV_ARG, JINT_ARG(width),
                  JINT_ARG(height))
  QIcon windowIcon = m_widget->windowIcon();
  bool visible = m_widget->isVisible();
  QPoint position = m_widget->pos();
  Qt::WindowFlags flags = m_widget->windowFlags();
  if ((width <= 0) || (height <= 0)) {
    m_widget->setMinimumSize(0, 0);
    m_widget->setMaximumSize(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX);
    if (flags & ~Qt::WindowMaximizeButtonHint) {
      m_widget->setWindowFlags(flags | Qt::WindowMaximizeButtonHint);
    }
  } else {
    m_widget->setFixedSize(width, height);
    if (flags & Qt::WindowMaximizeButtonHint) {
      m_widget->setWindowFlags(flags & ~Qt::WindowMaximizeButtonHint);
    }
  }
  m_widget->setWindowIcon(windowIcon);
  if (m_widget->pos() != position) {
    m_widget->move(position);
  }
  if (m_widget->isVisible() != visible) {
    m_widget->setVisible(visible);
  }
}

/*!
 * \brief Sets component's bounds.
 *
 * \param env the JNIEnv pointer 
 * \param x the x coordinate of the bounds
 * \param y the y coordinate of the bounds
 * \param width the width of the bounds
 * \param height the height of the bounds
 */
void ComponentDelegate::setBounds(JNIEnv *env, jint x, jint y, jint width,
                                  jint height)
{
  Q_ASSERT(env);
  SWING_REENTRANT(setBounds, SWING_ENV_ARG, JINT_ARG(x), JINT_ARG(y),
                  JINT_ARG(width), JINT_ARG(height))
  if (m_widget->isWindow()) {
    // resize problem workaround
    if (m_widget->testAttribute(Qt::WA_WState_ExplicitShowHide)) {
      QRect frameRect = m_widget->frameGeometry();
      QRect widgetRect = m_widget->geometry();
      int dw = frameRect.width() - widgetRect.width();
      int dh = frameRect.height() - widgetRect.height();
      m_widget->resize(width - dw, height - dh);
    } else {
      m_widget->resize(width, height);
      QRect rect = m_widget->frameGeometry();
      int dw = rect.width() - width;
      int dh = rect.height() - height;
      if ((dw > 0) || (dh > 0)) {
        m_widget->resize(width - dw, height - dh);
      }
    }
    m_widget->move(x, y);
  } else {
    m_widget->setGeometry(x, y, width, height);
  }
}

/*!
 * \brief Returns background color.
 *
 * \param env the JNIEnv pointer
 * \param colorClass the java color class
 *
 * \return background color
 */
jobject ComponentDelegate::getBackground(JNIEnv *env, jclass colorClass)
{
  return QColorAdapter::toJColor(env, colorClass,
                        m_widget->palette().color(m_widget->backgroundRole()));
}

/*!
 * \brief Sets the background color.
 *
 * \param env the JNIEnv pointer
 * \param argb the argb value of the color
 */
void ComponentDelegate::setBackground(JNIEnv *env, jint argb)
{
  Q_ASSERT(env);
  SWING_REENTRANT(setBackground, SWING_ENV_ARG, JINT_ARG(argb))
  QColorAdapter color(argb);
  QPalette palette(m_widget->palette());
  if (color.isValid()) {
    palette.setColor(m_widget->backgroundRole(), color);
  } else {
    palette.setColor(m_widget->backgroundRole(),
                     QApplication::palette().color(m_widget->backgroundRole()));
  }
  m_widget->setPalette(palette);
}

/*!
 * \brief Sets the application default background color.
 *
 * \param env the JNIEnv pointer
 */
void ComponentDelegate::setNullBackground(JNIEnv *env)
{
  Q_ASSERT(env);
  SWING_REENTRANT(setNullBackground, SWING_ENV_ARG)
  QPalette palette(m_widget->palette());
  palette.setColor(m_widget->backgroundRole(),
                   QApplication::palette().color(m_widget->backgroundRole()));
  m_widget->setPalette(palette);
}

/*!
 * \brief Returns foreground color.
 *
 * \param env the JNIEnv pointer
 * \param colorClass the Swing color class
 *
 * \return foreground color
 */
jobject ComponentDelegate::getForeground(JNIEnv *env, jclass colorClass)
{
  return QColorAdapter::toJColor(env, colorClass,
                        m_widget->palette().color(m_widget->foregroundRole()));
}

/*!
 * \brief Sets the foreground color.
 *
 * \param env the JNIEnv pointer
 * \param argb the argb value of the color
 */
void ComponentDelegate::setForeground(JNIEnv *env, jint argb)
{
  Q_ASSERT(env);
  SWING_REENTRANT(setForeground, SWING_ENV_ARG, JINT_ARG(argb))
  QColorAdapter color(argb);
  QPalette palette(m_widget->palette());
  if (color.isValid()) {
    palette.setColor(m_widget->foregroundRole(), color);
  } else {
    palette.setColor(m_widget->foregroundRole(),
                     QApplication::palette().color(m_widget->foregroundRole()));
  }
  m_widget->setPalette(palette);
}

/*!
 * \brief Sets the application default foreground color.
 *
 * \param env the JNIEnv pointer
 */
void ComponentDelegate::setNullForeground(JNIEnv *env)
{
  Q_ASSERT(env);
  SWING_REENTRANT(setNullForeground, SWING_ENV_ARG)
  QPalette palette(m_widget->palette());
  palette.setColor(m_widget->foregroundRole(),
                   QApplication::palette().color(m_widget->foregroundRole()));
  m_widget->setPalette(palette);
}

/*!
 * \brief Sets whether or not Swing object paints all background.
 *
 * \param env the JNIEnv pointer
 * \param opaque \c true if the object should paint all background
 */
void ComponentDelegate::setOpaque(JNIEnv *env, jboolean opaque)
{
  Q_ASSERT(env);
  SWING_REENTRANT(setOpaque, SWING_ENV_ARG, JBOOLEAN_ARG(opaque))
  m_widget->setAutoFillBackground(opaque);
}

/*!
 * \brief Returns font.
 *
 * \param env the JNIEnv pointer
 * \param fontClass the Swing font class
 *
 * \return font
 */
jobject ComponentDelegate::getFont(JNIEnv *env, jclass fontClass)
{
  return QFontAdapter::toJFont(env, fontClass, m_widget->font());
}

/*!
 * \brief Sets the font.
 *
 * \param env the JNIEnv pointer
 * \param font the Swing font
 */
void ComponentDelegate::setFont(JNIEnv *env, jobject font)
{
  Q_ASSERT(env);
  SWING_REENTRANT(setFont, SWING_ENV_ARG, JOBJECT_ARG(font))
  if (font) {
    m_widget->setFont(*QFontAdapter::toQFont(env, font));
  } else {
    m_widget->setFont(QFont());
  }
}

/*!
 * \brief Sets style sheet.
 *
 * \param env the JNIEnv pointer 
 * \param styleSheetText the style sheet text
 */
void ComponentDelegate::setStyleSheet(JNIEnv *env, jstring styleSheetText)
{
  Q_ASSERT(env);
  SWING_REENTRANT(setStyleSheet, SWING_ENV_ARG, JSTRING_ARG(styleSheetText))
  m_widget->setStyleSheet(QStringAdapter(env, styleSheetText));
}

/*!
 * \brief Sets style sheet properties.
 *
 * \param env the JNIEnv pointer 
 */
void ComponentDelegate::setStyleSheetProperties(JNIEnv *env)
{
  Q_ASSERT(env);
  SWING_REENTRANT(setStyleSheetProperties, SWING_ENV_ARG)
  fillStyleSheetProperties(env, &STYLE_SHEET_PROPERTY_VALUE);
}

/*!
 * \brief Removes style sheet properties.
 *
 * \param env the JNIEnv pointer
 */
void ComponentDelegate::removeStyleSheetProperties(JNIEnv *env)
{
  Q_ASSERT(env);
  SWING_REENTRANT(removeStyleSheetProperties, SWING_ENV_ARG)
  fillStyleSheetProperties(env, &INVALID_QVARIANT);
}

/*!
 * \brief Returns current cursor.
 *
 * \param env the JNIEnv pointer 
 *
 * \return current cursor
 */
jint ComponentDelegate::getCursor(JNIEnv *env)
{
  Q_UNUSED(env);
  return QCursorAdapter::cursorType(m_widget->cursor());
}

/*!
 * \brief Sets cursor.
 *
 * \param env the JNIEnv pointer 
 * \param type the type of the cursor
 */
void ComponentDelegate::setCursor(JNIEnv *env, jint type)
{
  Q_ASSERT(env);
  SWING_REENTRANT(setCursor, SWING_ENV_ARG, JINT_ARG(type))
  if (type < 0) {
    m_widget->unsetCursor();
  } else {
    m_widget->setCursor(QCursorAdapter(type));
  }
}

/*!
 * \brief Repaints the component.
 *
 * \param env the JNIEnv pointer 
 */
void ComponentDelegate::repaint(JNIEnv *env)
{
  Q_ASSERT(env);
  SWING_REENTRANT(repaint, SWING_ENV_ARG)
  m_widget->repaint();
}

/*!
 * \brief Repaints the component region.
 *
 * \param env the JNIEnv pointer
 * \param x the x coordinate of the region
 * \param y the y coordinate of the region
 * \param width the width of the region
 * \param height the height of the region
 */
void ComponentDelegate::repaint(JNIEnv *env, jint x, jint y, jint width,
                                jint height)
{
  Q_ASSERT(env);
  SWING_REENTRANT(repaint, SWING_ENV_ARG, JINT_ARG(x), JINT_ARG(y),
                  JINT_ARG(width), JINT_ARG(height))
  m_widget->repaint(x, y, width, height);
}

/*!
 * \brief Updates the component.
 *
 * \param env the JNIEnv pointer 
 */
void ComponentDelegate::update(JNIEnv *env)
{
  Q_ASSERT(env);
  SWING_REENTRANT(update, SWING_ENV_ARG)
  m_widget->update();
}

/*!
 * \brief Updates the component region.
 *
 * \param env the JNIEnv pointer 
 * \param x the x coordinate of the region
 * \param y the y coordinate of the region
 * \param width the width of the region
 * \param height the height of the region
 */
void ComponentDelegate::update(JNIEnv *env, jint x, jint y, jint width,
                               jint height)
{
  Q_ASSERT(env);
  SWING_REENTRANT(update, SWING_ENV_ARG, JINT_ARG(x), JINT_ARG(y),
                  JINT_ARG(width), JINT_ARG(height))
  m_widget->update(x, y, width, height);
}

/*!
 * \brief Enables/disables updates.
 *
 * \param env the JNIEnv pointer 
 * \param enabled \c true if enabled
 */
void ComponentDelegate::setUpdatesEnabled(JNIEnv *env, jboolean enabled)
{
  Q_ASSERT(env);
  SWING_REENTRANT(setUpdatesEnabled, SWING_ENV_ARG, JBOOLEAN_ARG(enabled))
  m_widget->setUpdatesEnabled(enabled);
}

/*!
 * \brief Polishes the component.
 *
 * \param env the JNIEnv pointer 
 */
void ComponentDelegate::polish(JNIEnv *env)
{
  Q_UNUSED(env);
  qApp->postEvent(qObject(), new QEvent(QEvent::Polish));
}

/*!
 * \brief Sets the Swing object orientation.
 *
 * \param env the JNIEnv pointer
 * \param orientation the object orientation
 */
void ComponentDelegate::setComponentOrientation(JNIEnv *env, jint orientation)
{
  Q_ASSERT(env);
  SWING_REENTRANT(setComponentOrientation, SWING_ENV_ARG, JINT_ARG(orientation))
  switch(orientation) {
    case 1:
      m_widget->unsetLayoutDirection();
      break;
    case 4:
      m_widget->setLayoutDirection(Qt::LeftToRight);
      break;
    default:
      m_widget->setLayoutDirection(Qt::RightToLeft);
      break;
  }
}

/*!
 * \brief Sets tool tip text.
 *
 * \param env the JNIEnv pointer
 * \param text the tool tip text
 */
void ComponentDelegate::setToolTipText(JNIEnv *env, jstring text)
{
  Q_ASSERT(env);
  SWING_REENTRANT(setToolTipText, SWING_ENV_ARG, JSTRING_ARG(text))
  m_widget->setToolTip(QStringAdapter(env, text));
}

/*!
 * \brief Sets status tip text.
 *
 * \param env the JNIEnv pointer
 * \param text the status tip text
 */
void ComponentDelegate::setStatusTipText(JNIEnv *env, jstring text)
{
  Q_ASSERT(env);
  SWING_REENTRANT(setStatusTipText, SWING_ENV_ARG, JSTRING_ARG(text))
  m_widget->setStatusTip(QStringAdapter(env, text));
}

/*!
 * \brief Sets what's this text.
 *
 * \param env the JNIEnv pointer
 * \param text the what's this text
 */
void ComponentDelegate::setWhatsThisText(JNIEnv *env, jstring text)
{
  Q_ASSERT(env);
  SWING_REENTRANT(setWhatsThisText, SWING_ENV_ARG, JSTRING_ARG(text))
  m_widget->setWhatsThis(QStringAdapter(env, text));
}

/*!
 * \brief Enables specified events.
 *
 * \param env the JNIEnv pointer
 * \param events the events to be enabled
 */
void ComponentDelegate::setEnabledEvents(JNIEnv *env, jlong events)
{
  Q_ASSERT(env);
  SWING_REENTRANT(setEnabledEvents, SWING_ENV_ARG, JLONG_ARG(events))
  m_enabledEvents = events;
  filterEnabledEvents();
}

/*!
 * \brief Paints the component.
 *
 * \param env the JNIEnv pointer 
 * \param graphicsPointer the graphics pointer
 */
void ComponentDelegate::paintComponent(JNIEnv *env, jlong graphicsPointer)
{
  Q_UNUSED(env);
  if (m_paintEvent) {
    swingGraphics->push();
    static_cast<QObject *>(paintingWidget())->event(m_paintEvent);
    swingGraphics->pop();
  }
}

// ComponentDelegate :: Static Native Calls. -----------------------------------

/*!
 * \brief Initializes ComponentDelegate class.
 *
 * \param env the JNIEnv pointer
 * \param cls the Component java class
 *
 * \exception FatalError if failed
 */
void ComponentDelegate::initialize(JNIEnv *env, jclass cls)
{
  Q_ASSERT(env);
  Q_ASSERT(cls);
  Q_ASSERT(!sm_delegateFID);
  if (!INIT_UFID(delegate, cls, "J") ||
      !INIT_UMID(create, cls, "()J") ||
      !INIT_UMID(visibleChanged, cls, "(Z)V") ||
      !INIT_UMID(enabledChanged, cls, "(Z)V") ||
      !INIT_CLASS(abstractDisposable, env->GetSuperclass(cls)) ||
      !INIT_NMID(classGetName, env->GetObjectClass(cls), "getName",
                 "()Ljava/lang/String;") ||
      !INIT_MID(getPreferredSize, cls,
                "()Lcom/cute4j/swing/graphics/Dimension;") ||
      !INIT_UMID(positionChanged, cls, "(II)V") ||
      !INIT_UMID(sizeChanged, cls, "(II)V") ||
      !INIT_UMID(paint, cls, "(J)V") ||
      !INIT_UMID(styleChanged, cls, "()V") ||
      !INIT_UMID(styleSheetChanged, cls, "(Z)V") ||
      !INIT_UMID(focusGained, cls, "()V") ||
      !INIT_UMID(focusLost, cls, "()V") ||
      !INIT_UMID(keyPressed, cls, "(IIC)V") ||
      !INIT_UMID(keyReleased, cls, "(IIC)V") ||
      !INIT_UMID(keyTyped, cls, "(IIC)V") ||
      !INIT_UMID(mouseEntered, cls, "(IIII)V") ||
      !INIT_UMID(mouseExited, cls, "(IIII)V") ||
      !INIT_UMID(mousePressed, cls, "(IIII)V") ||
      !INIT_UMID(mouseReleased, cls, "(IIII)V") ||
      !INIT_UMID(mouseClicked, cls, "(IIII)V") ||
      !INIT_UMID(mouseDoubleClicked, cls, "(IIII)V") ||
      !INIT_UMID(contextMenuTriggered, cls, "(IIIIII)V") ||
      !INIT_UMID(mouseMoved, cls, "(IIII)V") ||
      !INIT_UMID(mouseDragged, cls, "(IIII)V") ||
      !INIT_UMID(mouseWheelMoved, cls, "(IIII)V") ||
      !INIT_MID(getToolTipText, cls, "(II)Ljava/lang/String;")) {
    FATAL_LOGGED_ERROR("ComponentDelegate initialization failed");
  }
}

/*!
 * \brief Returns new instance of the delegate object.
 *
 * \param env the JNIEnv pointer 
 * \param obj the Swing object
 * 
 * \return new instance of the delegate object
 */
jlong ComponentDelegate::newInstance(JNIEnv *env, jobject obj)
{
  if (JNISwingWrapper::isSwingThread(env)) {
    return reinterpret_cast<jlong>(new ComponentDelegate(env, obj));
  }
  return SwingUtilitiesDelegate::invokeLongAndWait(env, obj, createMID());
}

// ComponentDelegate :: Native Callbacks. --------------------------------------

/*!
 * \brief Calls \c visibleChanged method of the Component java object.
 *
 * \param visible \c true if visible
 */
void ComponentDelegate::visibleChanged(bool visible)
{
  jniObject()->callVoidMethod(sm_visibleChangedMID, visible);
}

/*!
 * \brief Calls \c enabledChanged method of the Component java object.
 *
 * \param enabled \c true if enabled
 */
void ComponentDelegate::enabledChanged(bool enabled)
{
  jniObject()->callVoidMethod(sm_enabledChangedMID, enabled);
}

/*!
 * \brief Calls \c positionChanged method of the Component java object.
 *
 * \param x the x coordinate of the new position
 * \param y the y coordinate of the new position
 */
void ComponentDelegate::positionChanged(jint x, jint y)
{
  jniObject()->callVoidMethod(sm_positionChangedMID, x, y);
}

/*!
 * \brief Calls \c sizeChanged method of the Component java object.
 *
 * \param width the new width of the component
 * \param height the new height of the component
 */
void ComponentDelegate::sizeChanged(jint width, jint height)
{
  jniObject()->callVoidMethod(sm_sizeChangedMID, width, height);
}

/*!
 * \brief Calls \c paint method of the Component java object.
 *
 * \param x the x coordinate of the rectangle to be painted
 * \param y the y coordinate of the rectangle to be painted
 * \param width the width coordinate of the rectangle to be painted
 * \param height the height coordinate of the rectangle to be painted
 */
void ComponentDelegate::paint(jint x, jint y, jint width, jint height)
{
  SwingGraphics graphics(paintingWidget(), x, y, width, height);
  jniObject()->callVoidMethod(sm_paintMID, reinterpret_cast<jlong>(&graphics));
}

/*!
 * \brief Calls \c styleSheetChanged method of the Component java object.
 *
 * \param removed \c true if the style sheet has been removed
 */
void ComponentDelegate::styleSheetChanged(bool removed)
{
  jniObject()->callVoidMethod(sm_styleSheetChangedMID, removed);
}

/*!
 * \brief Calls \c styleChanged method of the Component java object.
 */
void ComponentDelegate::styleChanged()
{
  jniObject()->callVoidMethod(sm_styleChangedMID);
}

/*!
 * \brief Calls \c focusGained method of the Component java object.
 */
void ComponentDelegate::focusGained()
{
  jniObject()->callVoidMethod(sm_focusGainedMID);
}

/*!
 * \brief Calls \c focusLost method of the Component java object.
 */
void ComponentDelegate::focusLost()
{
  jniObject()->callVoidMethod(sm_focusLostMID);
}

/*!
 * \brief Calls \c keyPressed method of the Component java object.
 *
 * \param modifiers the modifiers
 * \param keyCode the key code
 * \param keyChar the key char
 */
void ComponentDelegate::keyPressed(jint modifiers, jint keyCode, jchar keyChar)
{
  jniObject()->callVoidMethod(sm_keyPressedMID, modifiers, keyCode, keyChar);
}

/*!
 * \brief Calls \c keyReleased method of the Component java object.
 *
 * \param modifiers the modifiers
 * \param keyCode the key code
 * \param keyChar the key char
 */
void ComponentDelegate::keyReleased(jint modifiers, jint keyCode, jchar keyChar)
{
  jniObject()->callVoidMethod(sm_keyReleasedMID, modifiers, keyCode, keyChar);
}

/*!
 * \brief Calls keyTyped method of the Component java object.
 *
 * \param modifiers the modifiers
 * \param keyCode the key code
 * \param keyChar the key char
 */
void ComponentDelegate::keyTyped(jint modifiers, jint keyCode, jchar keyChar)
{
  jniObject()->callVoidMethod(sm_keyTypedMID, modifiers, keyCode, keyChar);
}

/*!
 * \brief Calls \c mouseEntered method of the Component java object.
 *
 * \param button the mouse button
 * \param modifiers the modifiers
 * \param x the x coordinate of the mouse pointer
 * \param y the y coordinate of the mouse pointer
 */
void ComponentDelegate::mouseEntered(jint button, jint modifiers, jint x,
                                     jint y)
{
  jniObject()->callVoidMethod(sm_mouseEnteredMID, button, modifiers, x, y);
}

/*!
 * \brief Calls \c mouseExited method of the Component java object.
 *
 * \param button the mouse button
 * \param modifiers the modifiers
 * \param x the x coordinate of the mouse pointer
 * \param y the y coordinate of the mouse pointer
 */
void ComponentDelegate::mouseExited(jint button, jint modifiers, jint x,
                                    jint y)
{
  jniObject()->callVoidMethod(sm_mouseExitedMID, button, modifiers, x, y);
}

/*!
 * \brief Calls \c mousePressed method of the Component java object.
 *
 * \param button the mouse button
 * \param modifiers the modifiers
 * \param x the x coordinate of the mouse pointer
 * \param y the y coordinate of the mouse pointer
 */
void ComponentDelegate::mousePressed(jint button, jint modifiers, jint x,
                                     jint y)
{
  jniObject()->callVoidMethod(sm_mousePressedMID, button, modifiers, x, y);
}

/*!
 * \brief Calls \c mouseReleased method of the Component java object.
 *
 * \param button the mouse button
 * \param modifiers the modifiers
 * \param x the x coordinate of the mouse pointer
 * \param y the y coordinate of the mouse pointer
 */
void ComponentDelegate::mouseReleased(jint button, jint modifiers, jint x,
                                      jint y)
{
  jniObject()->callVoidMethod(sm_mouseReleasedMID, button, modifiers, x, y);
}

/*!
 * \brief Calls \c mouseClicked method of the Component java object.
 *
 * \param button the mouse button
 * \param modifiers the modifiers
 * \param x the x coordinate of the mouse pointer
 * \param y the y coordinate of the mouse pointer
 */
void ComponentDelegate::mouseClicked(jint button, jint modifiers, jint x,
                                     jint y)
{
  jniObject()->callVoidMethod(sm_mouseClickedMID, button, modifiers, x, y);
}

/*!
 * \brief Calls \c mouseDoubleClicked method of the Component java object.
 *
 * \param button the mouse button
 * \param modifiers the modifiers
 * \param x the x coordinate of the mouse pointer
 * \param y the y coordinate of the mouse pointer
 */
void ComponentDelegate::mouseDoubleClicked(jint button, jint modifiers, jint x,
                                           jint y)
{
  jniObject()->callVoidMethod(sm_mouseDoubleClickedMID, button, modifiers, x,
                              y);
}

/*!
 * \brief Calls \c contextMenuTriggered method of the Component java object.
 *
 * \param reason the reason
 * \param modifiers the modifiers
 * \param x the x coordinate of the mouse pointer
 * \param y the y coordinate of the mouse pointer
 * \param globalX the global x coordinate of the mouse pointer
 * \param globalY the global y coordinate of the mouse pointer
 */
void ComponentDelegate::contextMenuTriggered(jint reason, jint modifiers,
                                             jint x, jint y, jint globalX,
                                             jint globalY)
{
  jniObject()->callVoidMethod(sm_contextMenuTriggeredMID, reason, modifiers, x,
                              y, globalX, globalY);
}

/*!
 * \brief Calls \c mouseMoved method of the Component java object.
 *
 * \param button the mouse button
 * \param modifiers the modifiers
 * \param x the x coordinate of the mouse pointer
 * \param y the y coordinate of the mouse pointer
 */
void ComponentDelegate::mouseMoved(jint button, jint modifiers, jint x,
                                   jint y)
{
  jniObject()->callVoidMethod(sm_mouseMovedMID, button, modifiers, x, y);
}

/*!
 * \brief Calls \c mouseDragged method of the Component java object.
 *
 * \param button the mouse button
 * \param modifiers the modifiers
 * \param x the x coordinate of the mouse pointer
 * \param y the y coordinate of the mouse pointer
 */
void ComponentDelegate::mouseDragged(jint button, jint modifiers, jint x,
                                     jint y)
{
  jniObject()->callVoidMethod(sm_mouseDraggedMID, button, modifiers, x, y);
}

/*!
 * \brief Calls \c mouseDragged method of the Component java object.
 *
 * \param modifiers the modifiers
 * \param x the x coordinate of the mouse pointer
 * \param y the y coordinate of the mouse pointer
 * \param wheelRotation the wheel rotation
 */
void ComponentDelegate::mouseWheelMoved(jint modifiers, jint x, jint y,
                                        jint wheelRotation)
{
  jniObject()->callVoidMethod(sm_mouseWheelMovedMID, modifiers, x, y,
                              wheelRotation);
}

/*!
 * \brief Returns preferred size of the Swing component.
 *
 * \return preferred size of the Swing component
 */
QSize ComponentDelegate::getPreferredSize()
{
  jobject preferredSize;
  if (jniObject()->callObjectMethod(preferredSize, sm_getPreferredSizeMID)) {
    jint preferredWidth;
    jint preferredHeight;
    DimensionObject preferredSizeDimension(jniObject()->env(), preferredSize);
    if (preferredSizeDimension.getWidth(preferredWidth) &&
        preferredSizeDimension.getHeight(preferredHeight)) {
      return QSize(preferredWidth, preferredHeight);
    }
  }
  return QSize();
}

/*!
 * \brief Returns tooltip for the specified location.
 *
 * \param x the x-coordinate of the tooltip location
 * \param y the y-coordinate of the tooltip location
 *
 * \return tooltip for the specified location
 */
jstring ComponentDelegate::getToolTipText(int x, int y)
{
  jobject toolTipText;
  if (jniObject()->callObjectMethod(toolTipText, sm_getToolTipTextMID, x, y)) {
    return (jstring)toolTipText;
  }
  return 0;
}

// ComponentDelegate :: Public Member Functions. -------------------------------

/*!
 * \brief Sets parent delegate.
 *
 * \param parentDelegate the parent delegate
 */
void ComponentDelegate::setParentDelegate(ContainerDelegate *parentDelegate)
{
  m_parentDelegate = parentDelegate;
}

/*!
 * \brief Returns QWidget.
 *
 * \return QWidget
 */
QWidget *ComponentDelegate::qWidget()
{
  return m_widget;
}

/*!
 * \brief Returns widget action.
 *
 * \return widget action
 */
QAction *ComponentDelegate::qAction()
{
  if (!m_action) {
    m_action = new QWidgetActionAdapter(this);
  }
  return m_action;
}

// ComponentDelegate :: Protected Member Functions. ----------------------------

/*!
 * \brief Notifies delegate that an action is deleted.
 *
 * \param action the action
 */
void ComponentDelegate::widgetActionDeleted(QAction *action)
{
  if (action == m_action) {
    delete m_action;
    m_action = 0;
  }
}

/*!
 * \brief Filters the specified event.
 *
 * \param obj the object
 * \param e the event
 */
bool ComponentDelegate::filterEvent(QObject *obj, QEvent *e)
{
  switch ((int)e->type()) { // cast for QEvent::User types
    case QEvent::Show:
      return filterShowEvent(obj, static_cast<QShowEvent *>(e));
    case QEvent::Hide:
      return filterHideEvent(obj, static_cast<QHideEvent *>(e));
    case QEvent::EnabledChange:
      return filterEnabledChangeEvent(obj, e);
    case QEvent::PaletteChange:
      // falls through
    //case QEvent::StyleChange: // opt. - don't uncomment
      return filterStyleChangeEvent(obj, e);
    case QEvent::Resize:
      return filterResizeEvent(obj, static_cast<QResizeEvent *>(e));
    case QEvent::Move:
      return filterMoveEvent(obj, static_cast<QMoveEvent *>(e));
    case QEvent::Paint: {
        if (paintingWidget()->isVisible()) {
          if (eventEnabled(SWING_EVENT(PAINT_EVENT_MASK))) {
            m_paintEvent = static_cast<QPaintEvent *>(e);
            QRect rect = m_paintEvent->rect();
            paint(rect.x(), rect.y(), rect.width(), rect.height());
            m_paintEvent->accept();
            m_paintEvent = 0;
            return true;
          } else {
            return obj->event(e);
          }
        }
        return false;
      }
      break;
    case QEvent::FocusIn:
      return filterFocusGainedEvent(obj, static_cast<QFocusEvent *>(e));
    case QEvent::FocusOut:
      return filterFocusLostEvent(obj, static_cast<QFocusEvent *>(e));
    case QEvent::KeyPress:
      return filterKeyPressedEvent(obj, static_cast<QKeyEvent *>(e));
    case QEvent::KeyRelease:
      return filterKeyReleasedEvent(obj, static_cast<QKeyEvent *>(e));
    case SwingKeyTypedEvent::TYPE:
      return filterKeyTypedEvent(obj, static_cast<QKeyEvent *>(e));
    case QEvent::Enter:
      return filterMouseEnterEvent(obj, static_cast<QMouseEvent *>(e));
    case QEvent::MouseMove:
      return filterMouseMoveEvent(obj, static_cast<QMouseEvent *>(e));
    case QEvent::Leave:
      return filterMouseLeaveEvent(obj, static_cast<QMouseEvent *>(e));
    case QEvent::MouseButtonPress:
      return filterMousePressedEvent(obj, static_cast<QMouseEvent *>(e));
    case QEvent::MouseButtonRelease:
      return filterMouseReleasedEvent(obj, static_cast<QMouseEvent *>(e));
    case SwingMouseClickedEvent::TYPE:
      return filterMouseClickedEvent(obj, static_cast<QMouseEvent *>(e));
    case QEvent::MouseButtonDblClick:
      return filterMouseDoubleClickedEvent(obj, static_cast<QMouseEvent *>(e));
    case QEvent::Wheel:
      return filterMouseWheelEvent(obj, static_cast<QWheelEvent *>(e));
    case QEvent::ToolTip:
      return filterToolTipEvent(obj, static_cast<QHelpEvent *>(e));
    case QEvent::WhatsThis:
      return filterWhatsThisEvent(obj, static_cast<QHelpEvent *>(e));
    case QEvent::QueryWhatsThis:
      if (WhatsThisManagerDelegate::whatsThisEnabled()) {
        return obj->event(e);
      } else {
        e->ignore();
        return true;
      }
      break;
    case QEvent::ContextMenu:
      return filterContextMenuEvent(obj, static_cast<QContextMenuEvent *>(e));
    default:
      return false;
  }
}

/*!
 * \brief Filters show event.
 *
 * \param obj the object
 * \param e the show event
 */
bool ComponentDelegate::filterShowEvent(QObject *obj, QShowEvent *e)
{
  bool filtered = obj->event(e);
  visibleChanged(true);
  return filtered;
}

/*!
 * \brief Filters hide event.
 *
 * \param obj the object
 * \param e the hide event
 */
bool ComponentDelegate::filterHideEvent(QObject *obj, QHideEvent *e)
{
  bool filtered = obj->event(e);
  visibleChanged(false);
  return filtered;
}

/*!
 * \brief Filters enabled change event.
 *
 * \param obj the object
 * \param e the event
 */
bool ComponentDelegate::filterEnabledChangeEvent(QObject *obj, QEvent *e)
{
  bool filtered = obj->event(e);
  enabledChanged(m_widget->isEnabled());
  return filtered;
}

/*!
 * \brief Filters style change event.
 *
 * \param obj the object
 * \param e the event
 */
bool ComponentDelegate::filterStyleChangeEvent(QObject *obj, QEvent *e)
{
  bool filtered = obj->event(e);
  m_widget->updateGeometry();
  styleChanged();
  return filtered;
}

/*!
 * \brief Filters resize event.
 *
 * \param obj the object
 * \param e the resize event
 */
bool ComponentDelegate::filterResizeEvent(QObject *obj, QResizeEvent *e)
{
  bool filtered = obj->event(e);
  QSize newSize = e->size();
  sizeChanged(newSize.width(), newSize.height());
  return filtered;
}

/*!
 * \brief Filters move event.
 *
 * \param obj the object
 * \param e the move event
 */
bool ComponentDelegate::filterMoveEvent(QObject *obj, QMoveEvent *e)
{
  bool filtered = obj->event(e);
  QPoint newPoint = e->pos();
  positionChanged(newPoint.x(), newPoint.y());
  return filtered;
}

/*!
 * \brief Filters focus gained event.
 *
 * \param obj the object
 * \param e the focus event
 */
bool ComponentDelegate::filterFocusGainedEvent(QObject *obj, QFocusEvent *e)
{
  bool filtered = obj->event(e);
  focusGained();
  return filtered;
}

/*!
 * \brief Filters focus lost event.
 *
 * \param obj the object
 * \param e the focus event
 */
bool ComponentDelegate::filterFocusLostEvent(QObject *obj, QFocusEvent *e)
{
  bool filtered = obj->event(e);
  focusLost();
  return filtered;
}

/*!
 * \brief Filters key pressed event.
 *
 * \param obj the object
 * \param e the key event
 */
bool ComponentDelegate::filterKeyPressedEvent(QObject *obj, QKeyEvent *e)
{
  bool filtered = obj->event(e);
  if (eventEnabled(SWING_EVENT(KEY_EVENT_MASK))) {
    keyPressed(SwingDelegate::toSwingModifiers(e->modifiers()),
               SwingDelegate::toSwingKeyCode(e->key()),
               SwingDelegate::getSwingKeyChar(e));
    m_previousKey = e->key();
  }
  return filtered;
}

/*!
 * \brief Filters key released event.
 *
 * \param obj the object
 * \param e the key event
 */
bool ComponentDelegate::filterKeyReleasedEvent(QObject *obj, QKeyEvent *e)
{
  bool filtered = obj->event(e);
  if (eventEnabled(SWING_EVENT(KEY_EVENT_MASK))) {
    keyReleased(SwingDelegate::toSwingModifiers(e->modifiers()),
                SwingDelegate::toSwingKeyCode(e->key()),
                SwingDelegate::getSwingKeyChar(e));
    if ((m_previousEventType == QEvent::KeyPress) &&
        (m_previousKey == e->key())) {
      postEvent(new SwingKeyTypedEvent(e));
    }
    m_previousKey = 0;
  }
  return filtered;
}

/*!
 * \brief Filters key typed event.
 *
 * \param obj the object
 * \param e the key event
 */
bool ComponentDelegate::filterKeyTypedEvent(QObject *obj, QKeyEvent *e)
{
  Q_UNUSED(obj);
  if (eventEnabled(SWING_EVENT(KEY_EVENT_MASK))) {
    keyTyped(SwingDelegate::toSwingModifiers(e->modifiers()),
             SwingDelegate::toSwingKeyCode(e->key()),
             SwingDelegate::getSwingKeyChar(e));
    e->accept();
  }
  return true;
}

/*!
 * \brief Filters mouse enter event.
 *
 * \param obj the object
 * \param e the mouse event
 */
bool ComponentDelegate::filterMouseEnterEvent(QObject *obj, QMouseEvent *e)
{
  bool filtered = obj->event(e);
  if (eventEnabled(SWING_EVENT(MOUSE_EVENT_MASK))) {
    mouseEntered(SwingDelegate::toSwingButton(e->button()),
                 SwingDelegate::toSwingModifiers(e->modifiers()), e->x(),
                 e->y());
  }
  return filtered;
}

/*!
 * \brief Filters mouse moved event.
 *
 * \param obj the object
 * \param e the mouse event
 */
bool ComponentDelegate::filterMouseMoveEvent(QObject *obj, QMouseEvent *e)
{
  bool filtered = obj->event(e);
  if (eventEnabled(SWING_EVENT(MOUSE_MOTION_EVENT_MASK))) {
    if (m_previousMouseButton) {
      mouseDragged(SwingDelegate::toSwingButton(m_previousMouseButton),
                   SwingDelegate::toSwingModifiers(e->modifiers()), e->x(),
                   e->y());
    } else {
      mouseMoved(0, SwingDelegate::toSwingModifiers(e->modifiers()), e->x(),
                 e->y());
    }
  }
  return filtered;
}

/*!
 * \brief Filters mouse leave event.
 *
 * \param obj the object
 * \param e the mouse event
 */
bool ComponentDelegate::filterMouseLeaveEvent(QObject *obj, QMouseEvent *e)
{
  bool filtered = obj->event(e);
  if (eventEnabled(SWING_EVENT(MOUSE_EVENT_MASK))) {
    mouseExited(SwingDelegate::toSwingButton(e->button()),
                SwingDelegate::toSwingModifiers(e->modifiers()), e->x(),
                e->y());
  }
  return filtered;
}

/*!
 * \brief Filters mouse button pressed event.
 *
 * \param obj the object
 * \param e the mouse event
 */
bool ComponentDelegate::filterMousePressedEvent(QObject *obj, QMouseEvent *e)
{
  bool filtered = obj->event(e);
  if (eventEnabled(SWING_EVENT(MOUSE_EVENT_MASK))) {
    m_previousMouseX = e->x();
    m_previousMouseY = e->y();
    mousePressed(SwingDelegate::toSwingButton(e->button()),
                 SwingDelegate::toSwingModifiers(e->modifiers()),
                 m_previousMouseX, m_previousMouseY);
    m_previousMouseButton = e->button();
  }
  return filtered;
}

/*!
 * \brief Filters mouse button released event.
 *
 * \param obj the object
 * \param e the mouse event
 */
bool ComponentDelegate::filterMouseReleasedEvent(QObject *obj, QMouseEvent *e)
{
  bool filtered = obj->event(e);
  if (eventEnabled(SWING_EVENT(MOUSE_EVENT_MASK))) {
    mouseReleased(SwingDelegate::toSwingButton(e->button()),
                  SwingDelegate::toSwingModifiers(e->modifiers()), e->x(),
                  e->y());
    if ((m_previousMouseButton == e->button()) &&
        (m_previousMouseX == e->x()) && (m_previousMouseY == e->y())) {
      postEvent(new SwingMouseClickedEvent(e));
    }
    m_previousMouseX = e->x();
    m_previousMouseY = e->y();
    m_previousMouseButton = Qt::NoButton;
  }
  return filtered;
}

/*!
 * \brief Filters mouse button clicked event.
 *
 * \param obj the object
 * \param e the mouse event
 */
bool ComponentDelegate::filterMouseClickedEvent(QObject *obj, QMouseEvent *e)
{
  Q_UNUSED(obj);
  if (eventEnabled(SWING_EVENT(MOUSE_EVENT_MASK))) {
    mouseClicked(SwingDelegate::toSwingButton(e->button()),
                 SwingDelegate::toSwingModifiers(e->modifiers()), e->x(),
                 e->y());
    e->accept();
  }
  return true;
}

/*!
 * \brief Filters mouse button double clicked event.
 *
 * \param obj the object
 * \param e the mouse event
 */
bool ComponentDelegate::filterMouseDoubleClickedEvent(QObject *obj,
                                                      QMouseEvent *e)
{
  bool filtered = obj->event(e);
  if (eventEnabled(SWING_EVENT(MOUSE_EVENT_MASK))) {
    mouseDoubleClicked(SwingDelegate::toSwingButton(e->button()),
                       SwingDelegate::toSwingModifiers(e->modifiers()), e->x(),
                       e->y());
  }
  return filtered;
}

/*!
 * \brief Filters mouse wheel event.
 *
 * \param obj the object
 * \param e the wheel event
 */
bool ComponentDelegate::filterMouseWheelEvent(QObject *obj, QWheelEvent *e)
{
  bool filtered = obj->event(e);
  if (eventEnabled(SWING_EVENT(MOUSE_WHEEL_EVENT_MASK))) {
    mouseWheelMoved(SwingDelegate::toSwingModifiers(e->modifiers()), e->x(),
                    e->y(), e->delta() / -120);
  }
  return filtered;
}

/*!
 * \brief Filters tooltip event.
 *
 * \param obj the object
 * \param e the help event
 */
bool ComponentDelegate::filterToolTipEvent(QObject *obj, QHelpEvent *e)
{
  if (ToolTipDelegate::toolTipsEnabled()) {
    if (eventEnabled(SWING_EVENT(LOCATION_TOOL_TIP_MASK))) {
      if (m_widget->isEnabled()) {
        jstring toolTipText = getToolTipText(e->x(), e->y());
        if (toolTipText) {
          QToolTip::showText(e->globalPos(), SwingString(toolTipText),
                             m_widget);
        } else {
          QToolTip::hideText();
        }
      }
      return true;
    } else {
      return obj->event(e);
    }
  } else {
    e->ignore();
    return true;
  }
}

/*!
 * \brief Filters what's this event.
 *
 * \param obj the object
 * \param e the help event
 */
bool ComponentDelegate::filterWhatsThisEvent(QObject *obj, QHelpEvent *e)
{
  if (WhatsThisManagerDelegate::whatsThisEnabled()) {
    return obj->event(e);
  } else {
    e->ignore();
    return true;
  }
}

/*!
 * \brief Filters context menu event.
 *
 * \param obj the object
 * \param e the context menu event
 */
bool ComponentDelegate::filterContextMenuEvent(QObject *obj,
                                               QContextMenuEvent *e)
{
  if (eventEnabled(SWING_EVENT(CONTEXT_MENU_EVENT_MASK))) {
    if (eventEnabled(SWING_EVENT(CUSTOM_CONTEXT_MENU_EVENT_MASK))) {
      contextMenuTriggered((jint)e->reason(),
                           SwingDelegate::toSwingModifiers(e->modifiers()),
                           e->x(), e->y(), e->globalX(), e->globalY());
      e->accept();
      return true;
    }
    return obj->event(e);
  }
  return false;
}

/*!
 * \brief Filters enabled events.
 */
void ComponentDelegate::filterEnabledEvents()
{
  if (eventEnabled(SWING_EVENT(MOUSE_MOTION_EVENT_MASK))) {
    m_widget->setMouseTracking(true);
  }
}

/*!
 * \brief Painting widget.
 *
 * \return painting widget
 */
QWidget *ComponentDelegate::paintingWidget()
{
  return m_widget;
}

// ComponentDelegate :: Overridden Member Functions. ---------------------------

/*!
 * \inheritDoc
 */
void ComponentDelegate::destroy(JNIEnv *env, bool notify)
{
  Q_UNUSED(env);
  setNotifyDelete(notify);
  if (SwingDelegate::isDisposed()) {
    delete this; // OK - referenced only from java
  } else {
    deleteLater();
  }
}

/*!
 * \brief Returns delegate pointer FID.
 *
 * \return delegate pointer FID 
 */
jfieldID ComponentDelegate::delegatePointerFID() const
{
  return sm_delegateFID;
}

/*!
 * \brief Filters events of the qObject.
 *
 * \param obj the qObject
 * \param e the event
 *
 * \return \c true if the event is filtered
 */
bool ComponentDelegate::eventFilter(QObject *obj, QEvent *e)
{
  bool filtered = false;
  if (m_eventFilterEnabled) {
    m_currentEvent = e;
    filtered = filterEvent(obj, e);
    m_previousEventType = e->type();
    m_currentEvent = 0;
  }
  return filtered;
}

// ComponentDelegate :: Private Member Function. -------------------------------

void ComponentDelegate::fillStyleSheetProperties(JNIEnv *env,
                                                 const QVariant *value)
{
  // TODO: needs clean up, check object releasing
  jclass cls = env->GetObjectClass(jniObject()->ref());
  char propertyName[128] = "QS_";
  do {
    jstring className = (jstring)env->CallObjectMethod(cls, sm_classGetNameMID);
    jsize classNameLen = env->GetStringLength(className);
    if (classNameLen > 120) {
      classNameLen = 120;
    }
    env->GetStringUTFRegion(className, 0, classNameLen, &propertyName[3]);
    for (int i = classNameLen + 3; --i >= 3;) {
      if (propertyName[i] == '.') {
        propertyName[i] = '_';
      }
    }
    qObject()->setProperty(propertyName, *value);
    cls = env->GetSuperclass(cls);
  } while (!env->IsSameObject(cls, sm_abstractDisposableClass));
}

// ComponentDelegate :: Private Static Data Members. ---------------------------

jfieldID ComponentDelegate::sm_delegateFID = 0;
jmethodID ComponentDelegate::sm_createMID = 0;
jmethodID ComponentDelegate::sm_visibleChangedMID = 0;
jmethodID ComponentDelegate::sm_enabledChangedMID = 0;
jclass ComponentDelegate::sm_abstractDisposableClass = 0;
jmethodID ComponentDelegate::sm_classGetNameMID = 0;
jmethodID ComponentDelegate::sm_getPreferredSizeMID = 0;
jmethodID ComponentDelegate::sm_sizeChangedMID = 0;
jmethodID ComponentDelegate::sm_positionChangedMID = 0;
jmethodID ComponentDelegate::sm_paintMID = 0;
jmethodID ComponentDelegate::sm_styleChangedMID = 0;
jmethodID ComponentDelegate::sm_styleSheetChangedMID = 0;
jmethodID ComponentDelegate::sm_focusGainedMID = 0;
jmethodID ComponentDelegate::sm_focusLostMID = 0;
jmethodID ComponentDelegate::sm_keyPressedMID = 0;
jmethodID ComponentDelegate::sm_keyReleasedMID = 0;
jmethodID ComponentDelegate::sm_keyTypedMID = 0;
jmethodID ComponentDelegate::sm_mouseEnteredMID = 0;
jmethodID ComponentDelegate::sm_mouseExitedMID = 0;
jmethodID ComponentDelegate::sm_mousePressedMID = 0;
jmethodID ComponentDelegate::sm_mouseReleasedMID = 0;
jmethodID ComponentDelegate::sm_mouseClickedMID = 0;
jmethodID ComponentDelegate::sm_mouseDoubleClickedMID = 0;
jmethodID ComponentDelegate::sm_contextMenuTriggeredMID = 0;
jmethodID ComponentDelegate::sm_mouseMovedMID = 0;
jmethodID ComponentDelegate::sm_mouseDraggedMID = 0;
jmethodID ComponentDelegate::sm_getToolTipTextMID = 0;
jmethodID ComponentDelegate::sm_mouseWheelMovedMID = 0;

// ComponentDelegate :: Public Constant Member. --------------------------------

const QVariant ComponentDelegate::STYLE_SHEET_PROPERTY_VALUE("styleSheet");
